home *** CD-ROM | disk | FTP | other *** search
- /*
- ** UCLOCK.C
- **
- ** Contains routines to perform microsecond accuracy timing
- ** operations.
- **
- ** Adapted from public domain source originally by David L. Fox
- ** Modified by Bob Stout
- */
-
- #include "uclock.h"
-
- /* Constants */
-
- #define CONTVAL 0x34 /* == 00110100 Control byte for 8253 timer. */
- /* Sets timer 0 to 2-byte read/write, */
- /* mode 2, binary. */
- #define T0DATA 0x40 /* Timer 0 data port address. */
- #define TMODE 0x43 /* Timer mode port address. */
- #define BIOS_DS 0x40 /* BIOS data segment. */
- #define B_TIKP 0x6c /* Address of BIOS (18.2/s) tick count. */
- #define SCALE 10000 /* Scale factor for timer ticks. */
-
- /* The following values assume 18.2 BIOS ticks per second resulting from
- the 8253 being clocked at 1.19 MHz. */
-
- #define us_BTIK 54925 /* Micro sec per BIOS clock tick. */
- #define f_BTIK 4595 /* Fractional part of usec per BIOS tick. */
- #define us_TTIK 8381 /* Usec per timer tick * SCALE. (4/4.77 MHz) */
-
- static int init = 0;
-
- /*
- ** usec_clock()
- **
- ** An analog of the clock() function, usec_clock() returns a number of
- ** type uclock_t (defined in RBS.H) which represents the number of
- ** microseconds past midnight. Analogous to CLK_TCK is UCLK_TCK, the
- ** number which a usec_clock() reading must be divided by to yield
- ** a number of seconds.
- */
-
- uclock_t usec_clock(void)
- {
- unsigned char msb, lsb;
- unsigned int tim_ticks;
- static uclock_t last, init_count;
- static uclock_t far *c_ptr;
- uclock_t count, us_tmp;
-
- if (!init)
- {
- c_ptr = (uclock_t far *)MK_FP(BIOS_DS, B_TIKP);
- init = 1; /* First call, we have to set up timer. */
- int_off();
- outp(TMODE, CONTVAL); /* Write new control byte. */
- outp(T0DATA, 0); /* Initial count = 65636. */
- outp(T0DATA, 0);
- init_count = *c_ptr;
- int_on();
- return 0; /* First call returns zero. */
- }
-
- /* Read PIT channel 0 count - see text */
-
- int_off(); /* Don't want an interrupt while getting time. */
- outp(TMODE, 0); /* Latch count. */
- lsb = (unsigned char)inp(T0DATA); /* Read count. */
- msb = (unsigned char)inp(T0DATA);
-
- /* Get BIOS tick count (read BIOS ram directly for speed and
- to avoid turning on interrupts). */
-
- count = *c_ptr;
- int_on(); /* Interrupts back on. */
- if ((-1) == init) /* Restart count */
- {
- init_count = count;
- init = 1;
- }
-
- /* Merge PIT channel 0 count with BIOS tick count */
-
- if (count < init_count)
- count += last;
- else last = count;
- count -= init_count;
- tim_ticks = (unsigned)(-1) - ((msb << 8) | lsb);
- us_tmp = count * us_BTIK;
- return (us_tmp + ((long)tim_ticks * us_TTIK + us_tmp % SCALE) / SCALE);
- }
-
- /*
- ** restart_uclock()
- **
- ** Since usec_clock() bases its return value on a differential value,
- ** a potential exists for problems in programs which run continuously
- ** for more than 24 hours. In such an application, it's necessary, at
- ** least once a day, to reset usec_clock's starting count.
- */
-
- void restart_uclock(void)
- {
- if (init)
- init = -1;
- }
-